package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.service.AlbumAttributeValueService;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

import static com.atguigu.tingshu.common.constant.SystemConstant.ALBUM_STATUS_NO_PASS;
import static com.atguigu.tingshu.common.constant.SystemConstant.ALBUM_STATUS_REVIEWING;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;

    @Autowired
    private AlbumAttributeValueService albumAttributeValueService;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    /**
     * 保存专辑
     *
     * @param albumInfoVo
     * @param userId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo, Long userId) {
        //1.保存专辑信息
        //1.1 将前端提交VO转为PO
        AlbumInfo albumInfo = BeanUtil.copyProperties(albumInfoVo, AlbumInfo.class);
        //1.2 为其他字段赋值
        albumInfo.setUserId(userId);
        //1.3 设置专辑状态为待审核,对专辑信息中文本图片审核通过
        albumInfo.setStatus(ALBUM_STATUS_REVIEWING);
        //免费试听
        albumInfo.setTracksForFree(5);
        //1.3 执行保存专辑
        baseMapper.insert(albumInfo);
        Long albumId = albumInfo.getId();

        //2.保存专辑标签关系
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (CollectionUtil.isNotEmpty(albumAttributeValueVoList)) {
            //2.1 遍历集合，获取每个标签对象 转为PO对象
            List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueVoList
                    .stream()
                    .map(albumAttributeValueVo -> {
                        AlbumAttributeValue albumAttributeValue = BeanUtil.copyProperties(albumAttributeValueVo, AlbumAttributeValue.class);
                        albumAttributeValue.setAlbumId(albumId);
                        return albumAttributeValue;
                    })
                    .collect(Collectors.toList());
            //2.2 执行保存专辑标签关系 关联专辑ID insert into values(),(),(),()
            //批量保存方法只在业务层有提供,批量新增效率高于循环保存
            albumAttributeValueService.saveBatch(albumAttributeValueList);
        }
        //3.保存专辑四条统计信息 TODO :修改为批量新增
        this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_PLAY, 0);
        this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_SUBSCRIBE, 0);
        this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_BUY, 0);
        this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_COMMENT, 0);

        //4.对专辑中文本内容进行审核 异步审核
        vodService.reviewAlbumText(albumInfo);
        log.info("{}，调用异步方法去进行审核内容：", Thread.currentThread().getName());
    }


    @Autowired
    private VodService vodService;

    /**
     * 专辑统计保存
     *
     * @param albumId  专辑ID
     * @param statType 统计类型
     * @param statNum  统计数值 0401-播放量 0402-订阅量 0403-购买量 0403-评论数'
     */
    @Override
    public void saveAlbumInfoStat(Long albumId, String statType, int statNum) {
        AlbumStat albumStat = new AlbumStat();
        albumStat.setAlbumId(albumId);
        albumStat.setStatType(statType);
        albumStat.setStatNum(statNum);
        albumStatMapper.insert(albumStat);
    }

    /**
     * 分页条件查询当前登录用户专辑列表
     *
     * @param pageInfo
     * @param albumInfoQuery
     * @return
     */
    @Override
    public Page<AlbumListVo> findUserAlbumPage(Page<AlbumListVo> pageInfo, AlbumInfoQuery albumInfoQuery) {
        //方式1：调用业务层分页方法得到专辑列表，遍历专辑列表再分别查询统计信息 执行SQL太多效率低
        //方式2：执行自定义动态SQL，一条SQL查询到专辑以及专辑统计信息
        return baseMapper.findUserAlbumPage(pageInfo, albumInfoQuery);
    }

    /**
     * 根据专辑ID删除专辑相关信息
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAlbumInfo(Long id) {
        //1.根据专辑ID查询声音 判断是否包含声音，如果有则提示错误信息
        Long count = trackInfoMapper.selectCount(
                new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getAlbumId, id)
        );
        if (count > 0) {
            throw new GuiguException(500, "该专辑下关联声音");
        }

        //2.删除专辑信息
        baseMapper.deleteById(id);

        //3.根据专辑ID删除统计信息
        albumStatMapper.delete(
                new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId, id)
        );

        //4.根据专辑ID查询标签关系
        albumAttributeValueMapper.delete(
                new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, id)
        );
    }


    /**
     * 根据专辑ID查询专辑信息，包含标签列表
     *
     * @param id
     * @return
     */
    @Override
    public AlbumInfo getAlbumInfo(Long id) {
        //1.根据专辑ID查询专辑信息
        AlbumInfo albumInfo = baseMapper.selectById(id);

        //2.根据专辑ID查询标签列表
        LambdaQueryWrapper<AlbumAttributeValue> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AlbumAttributeValue::getAlbumId, id);
        List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueMapper.selectList(queryWrapper);
        if (CollectionUtil.isNotEmpty(albumAttributeValueList)) {
            albumInfo.setAlbumAttributeValueVoList(albumAttributeValueList);
        }
        return albumInfo;
    }

    /**
     * 更新专辑信息
     *
     * @param id
     * @param albumInfoVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAlbumInfo(Long id, AlbumInfoVo albumInfoVo) {
        //1.更新专辑信息表
        AlbumInfo albumInfo = BeanUtil.copyProperties(albumInfoVo, AlbumInfo.class);
        albumInfo.setStatus(ALBUM_STATUS_NO_PASS);
        albumInfo.setId(id);
        baseMapper.updateById(albumInfo);

        //2.更新专辑标签关系表
        //2.1 根据专辑ID删除原有专辑标签关系
        albumAttributeValueMapper.delete(
                new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, id)
        );
        //2.2 新增专辑标签关系
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (CollectionUtil.isNotEmpty(albumAttributeValueVoList)) {
            List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueVoList
                    .stream()
                    .map(albumAttributeValueVo -> {
                        AlbumAttributeValue albumAttributeValue = BeanUtil.copyProperties(albumAttributeValueVo, AlbumAttributeValue.class);
                        albumAttributeValue.setAlbumId(id);
                        return albumAttributeValue;
                    }).collect(Collectors.toList());
            //批量保存
            albumAttributeValueService.saveBatch(albumAttributeValueList);
        }

        //4.对专辑中文本内容进行审核 异步审核
        vodService.reviewAlbumText(albumInfo);
        log.info("{}，调用异步方法去进行审核内容：", Thread.currentThread().getName());
    }

    /**
     * 查询当前登录用户发布专辑列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        LambdaQueryWrapper<AlbumInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AlbumInfo::getUserId, userId);
        queryWrapper.eq(AlbumInfo::getStatus, SystemConstant.ALBUM_STATUS_PASS);
        queryWrapper.select(AlbumInfo::getId, AlbumInfo::getAlbumTitle);
        queryWrapper.last("limit 200");
        queryWrapper.orderByDesc(AlbumInfo::getId);
        return baseMapper.selectList(queryWrapper);
    }


    /**
     * a方法有事务，B方法没有事务，默认传播特性：Required B会自动加入到A事务中
     * <p>
     * 事务失效场景：
     * 1.MyISAM引擎不支持事务，数据表选择MyISAM引擎
     * 2.目标方法（业务层方法）执行发生异常，才会进行事务回滚。代码Catch到异常吞掉
     * 3.无法产生代理对象造成：事务底层AOP（1.JDK动态代理 2.CGLIB动态代理） private无法产生子类代理对象
     * 4.无事务方法a调用有事务环境方法b,通过控制层调用A方法不是代理对象，而是原始对象，所以事务失效  A中调用B方法调用原始对象方法
     * 5.方法被static,final关键字修饰，无法产生代理对象，归类所用
     */
    public void a() {
        //a表
        b();
    }

    @Transactional(rollbackFor = Exception.class)
    public void b() {
        //b表
    }
}
